#include "StdAfx.h"
#include "FileShellInfo.h"

using namespace Adaptive::Foundation::IO;

/*--------------------------------------------------------------------------------
 * Constructor / Dispose / Destructor Methods
 *------------------------------------------------------------------------------*/
#pragma region Constructor / Dispose / Destructor Methods
// Initializes a new instance of the class.
FileShellInfo::FileShellInfo()
{
}
#pragma endregion

/*--------------------------------------------------------------------------------
 * Public Methods / Functions
 *------------------------------------------------------------------------------*/
#pragma region Public Methods / Functions
/// Gets the file type description for the specified file.
String^ FileShellInfo::GetFileTypeDescription(String^ fileName)
{
	String^		definition = String::Empty;		//Registry file definition key.
	String^		extension = String::Empty;		//File extension.
	String^		returnValue = String::Empty;	//Return value.
	RegistryKey^ key = nullptr;					//Registry key.

	if ((fileName != nullptr) && (fileName->Length > 0))
	{
		//Get the extension and open the registry root key for the extension.
		extension = System::IO::Path::GetExtension(fileName);
		key = Registry::ClassesRoot->OpenSubKey(extension);
		if (key != nullptr)
		{
			//Read the actual info location for the related class.
			definition = (String^)key->GetValue(String::Empty, String::Empty);
			key->Close();
			delete(key);
		}

		if (definition->Length > 0)
		{
			//Open the class definition and read the description.
			key = Registry::ClassesRoot->OpenSubKey(definition);
			if (key != nullptr)
			{
				returnValue =(String^)key->GetValue(String::Empty, String::Empty);
				key->Close();
				delete(key);
			}
		}
	}

	if (returnValue->Length == 0)
		returnValue = "File";

	//Clear memory.
	key = nullptr;
	definition = nullptr;
	extension = nullptr;
	return returnValue;

}
/// Formats the value for display.
String^ FileShellInfo::FormatFileSize(__int64 originalSize)
{
	String^ returnValue = String::Empty;		//Return value.

	if (originalSize < 1024)
		returnValue = originalSize.ToString() + " bytes";
	else
		returnValue = 
			((float)(((float)originalSize)/1024)).ToString("###,###,###,###,##0.0##") + " KB";

	return returnValue;

}
/// Gets the application launch string from the registry for the specified 
/// file.
String^ FileShellInfo::GetRelatedApplication(String^ fileName)
{
	RegistryKey^ key = nullptr;						//Key to open and read.
	String^		returnValue = String::Empty;		//Return value.
	String^		extension = String::Empty;			//File extension.
	String^		location = String::Empty;			//Related registry data key name(s).
	int			index = -1;							//Character location index.

	//Get the related class key.
	extension = System::IO::Path::GetExtension(fileName);
	key = Registry::ClassesRoot->OpenSubKey(extension);
	if (key != nullptr)
	{
		//Read the related class ID value.
		location = (String^)key->GetValue(String::Empty, String::Empty);
		key->Close();
		delete(key);

		if (location->Length > 0)
		{
			//Open the related shell key.
			key = Registry::ClassesRoot->OpenSubKey(location + "\\shell\\edit\\command");
			if (key == nullptr)
				key = Registry::ClassesRoot->OpenSubKey(location + "\\shell\\Open\\command");

			if (key != nullptr)
			{
				//Read the application name.
				returnValue = (String^)key->GetValue(String::Empty, String::Empty);
				key->Close();
				delete(key);
			}
		}
	}

	//Parse out odd characters from string.
	if (returnValue->Length > 0)
	{
		//Remove the trailing flags.
		index = returnValue->IndexOf("\"");
		if (index > -1)
		{
			index = returnValue->IndexOf("\"", index+1);
			returnValue = returnValue->Substring(0, index+1);
		}

		//Remove other trailing flags.
		do
		{
			index = returnValue->LastIndexOf("%");
			if (index > -1)
				returnValue = returnValue->Substring(0, index);
		} while (index > -1);
				
		//Remove remaining characters.
		returnValue = returnValue->Replace("\"", String::Empty);
	}

	//Clear memory.
	key = nullptr;
	extension = nullptr;
	location = nullptr;

	return returnValue;

}
/// Gets the application launch string from the registry for the specified 
/// file.
String^ FileShellInfo::GetRelatedIconStore(String^ fileName)
{
	RegistryKey^ key = nullptr;					//Key to open and read.
	String^		returnValue = String::Empty;	//Return value.
	String^		extension = String::Empty;		//File extension.
	String^		location = String::Empty;		//Related registry data key name(s).
	int			index = -1;						//Character location index.

	//Get the related class key.
	extension = System::IO::Path::GetExtension(fileName);
	key = Registry::ClassesRoot->OpenSubKey(extension);
	if (key != nullptr)
	{
		//Read the related class ID value.
		location = (String^)key->GetValue(String::Empty, String::Empty);
		key->Close();
		delete(key);

		if (location->Length > 0)
		{
			//Open the related shell key.
			key = Registry::ClassesRoot->OpenSubKey(location + "\\DefaultIcon");

			if (key != nullptr)
			{
				//Read the application name.
				returnValue = (String^)key->GetValue(String::Empty, String::Empty);
				key->Close();
				delete(key);
			}
		}
	}

	//Parse out odd characters from string.
	if (returnValue->Length > 0)
	{
		//Remove the trailing flags.
		index = returnValue->IndexOf("\"");
		if (index > -1)
		{
			index = returnValue->IndexOf("\"", index+1);
			returnValue = returnValue->Substring(0, index+1);
		}

		//Remove other trailing flags.
		do
		{
			index = returnValue->LastIndexOf("%");
			if (index > -1)
				returnValue = returnValue->Substring(0, index);
		} while (index > -1);
				
		//Remove remaining characters.
		returnValue = returnValue->Replace("\"", String::Empty);
	}

	//Clear memory.
	key = nullptr;
	extension = nullptr;
	location = nullptr;

	return returnValue;

}
/// Gets the small icon used for the shell display.
Icon^ FileShellInfo::GetRelatedIcon(String^ fileName, bool large)
{
	CString widePath;								//Native name string.
	Icon^	returnValue = nullptr;					//Return value.
	String^ iconFile = String::Empty;				//File name.
	unsigned int flags = 0;							//Icon flags.
	SHFILEINFO* info = NULL;						//Icon Information buffer.
	unsigned int size = 0;							//Data size.
	int result = 0;
	int index = -1;
	int itemIndex = 0;

	iconFile = GetRelatedIconStore(fileName);
	index = iconFile->IndexOf(",");
	if (index > -1)
	{
		itemIndex = Convert::ToInt32(iconFile->Substring(index+1, iconFile->Length-(index+1)));
		iconFile = iconFile->Substring(0, index);
	}

	if (iconFile->Length == 0)
		iconFile = GetRelatedApplication(fileName);

	flags = SHGFI_ICON | SHGFI_SHELLICONSIZE | SHGFI_OPENICON | SHGFI_ATTRIBUTES | SHGFI_USEFILEATTRIBUTES;

	if (large)
		flags = flags | SHGFI_LARGEICON;
	else
		flags = flags | SHGFI_SMALLICON;

	info = new SHFILEINFO();
	size = sizeof(SHFILEINFO);

	widePath = iconFile;
	result = SHGetFileInfoW(
		widePath, FILE_ATTRIBUTE_NORMAL, info, size, flags);

	if ((result != 0) && (info->hIcon != NULL))
		returnValue = System::Drawing::Icon::FromHandle(IntPtr::IntPtr(info->hIcon));
	else
		returnValue = nullptr;

	delete(iconFile);

	return returnValue;
}
#pragma endregion